/*-------------------------------------------------------------------------
 - Copyright (c) 2024-2025 [XD-AMCC TEAM]
 - [XD-AMCC] is licensed under Mulan PSL v2.
 - You can use this software according to the terms and conditions of the Mulan PSL v2.
 - You may obtain a copy of Mulan PSL v2 at:
 -          http://license.coscl.org.cn/MulanPSL2
 - THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES
 - OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
 - TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 - See the Mulan PSL v2 for more details.
 ------------------------------------------------------------------------*/

/**
 * @brief  Declaration interface of IR-codes and code manager.
 *
 * @author  WXQ#XDU
 * @date    2025.01
 */

#pragma once

#ifndef AMCC_IRCODE_MGR_H
#define AMCC_IRCODE_MGR_H

#include "../../include/amcc_list.h"
#include "../../include/ircode.h"
#include "../../include/amcc_refcount.h"

#include "tempmgr.h"

AMCC_DECL_BEGIN


#define  INT_TO_PTR(type, id)  ((type)((ptrdiff_t)(id)))
#define  PTR_TO_INT(type,  p)  ((type)((ptrdiff_t)(p) & 0xFFFFFFFF))



//
//      Part  1     Declaration for  IR-code
//


typedef unsigned int t_ircode_id;  // type of the id of a Three-Address-Code

/**
 * Operation codes in Three-Address-Code
 */
typedef enum  opcode {
    OP_NULL ,        //!<  nothing

    #define IRCODE_DEF(c, t1, others...)  c
    #include "../../meta/_ir_opcode.inc"
    #undef IRCODE_DEF

} EnumOpCode;


/**
 * Enumerable address kinds in Three-Address-Codes
 */
typedef enum address_kind {
    AK_EMPTY = 0,   //!< nothing
    AK_TOKEN    ,   //!< a variable or literal in source-program
    AK_TEMPVAR  ,   //!< a compiler-generated temporary variable
    AK_IRCODE       //!< the id of an IR-code, or a small integer
} EnumAddrKind;


/**
 * Enumerable indexes of address in Three-Address-Codes
 */
typedef enum address_index {
    AI_ARG1,        //!<  index of arg1
    AI_ARG2,        //!<  index of arg2
    AI_RES ,        //!<  index of result
    AI_BAD =99      //!<  flag for error
} EnumAddrIndex;


/**
 * Structure of one address in a three-address-code.
 */
typedef struct ir_address {
    EnumAddrKind  addrKind;  // flag for value type
    union {
        // parse-tree node holding variable name or a literal.
        //     valid if addrKind is AK_TOKEN
        t_tree_ptr    treeNode;

        // temporary variable,
        //     valid if addrKind is AK_TEMPVAR
        t_tempvar_id  tempvarId;

        // target ir-code's id which used in all "** goto ___"
        // or a small integer,
        //     valid if addrKind is AK_IRCODE
        t_ircode_id   targetCodeId;
    } value;
} t_ir_address, * t_ir_address_ptr;


/** Class ircode representing a Three-Address-Code.

  In AMCC, Three-Address-Codes are implemented as quadruples with id,
  like "id: (op, arg1, arg2, result)".

  - For a binary op, the quad means "result = arg1 op arg2";
  - For a unary  op, the quad means "result = op arg1";
  - For an assignment, the quad means "result = arg1";
  - For accessing to array elements, the quad means
       "arg1[arg2]=result",  or  "result=arg1[arg2]";
  - For an actual parameter, the quad means "param arg1";
  - For a call  op, the quad means "result = call arg1, arg2"
        or "call arg1, arg2"  ;
  - For a return op, the quad means "return result" if arg1 is non-zero,
        or "return" if arg1 is zero;
  - For a conditional goto, the quad means "if arg1 rel_op arg2 goto result",
        or "if arg1 goto result" if arg2 is empty.
  - For an unconditional goto, the quad means "goto result".
*/
typedef struct ircode {
    t_ircode_id   id;         //!<  unique id of this ir-code

    EnumOpCode    opcode;     //!<  operation  code

    // Indexed by  names in EnumAddrIndex
    t_ir_address_ptr  address[3]; //!<  three addresses

    struct {
        char   isConstant;  //!< non-zero for a destroyable string
        const char * text;  //!< output message
    } comment;    //!< output message in IR-code file

} t_ircode, * t_ircode_ptr;



//
//      Part  2     Declaration for management of IR-codes
//


/**
 * Class attributes for syntactic structure.
 *
 * All instances of this class are attached to parse tree nodes.
 *
 * See t_tree.pAnnotation in file tree.h.
 */
typedef struct  code_attribute {
    t_reference      base;   // base class as member object

// local attributes for syntactic structure

    t_ir_address_ptr place;  //!< attribute .place for expr, var,
                             //!< also the EL.array for array element
    t_ir_address_ptr offset; //!< attribute .offset for array element,
                             //!< also the EL.place for array element
    t_type_ptr       type;   //!< expression type

// Chains are for back-patching tech:

    t_list_ptr  trueChain;  //!< attribute .tc of boolean expr
    t_list_ptr  falseChain; //!< attribute .fc of boolean expr

    t_list_ptr  nextChain;    //!< attribute .nc of statement
    t_ircode_id firstCodeId;  //!< first code id of statement

} t_codeattr, * t_codeattr_ptr;

// Whether an expression is boolean. ONLY works for Short-Circuit style
#define EXPR_IS_BOOL(E_attr_ptr)    (NULL == (E_attr_ptr)->place)

// Whether an expression is arithmetic, NOT boolean
#define EXPR_IS_ARITH(E_attr_ptr)   (NULL != (E_attr_ptr)->place)


/**
 * Creates a new attribute object.
 *
 * @note Caller should use tree_set_annotation() to record
 *       the returned object in parse tree node.
 *
 * @note The returned object should be destroyed through codeattr_destroy().
 *
 * @return  pointer to the new attribute object.
 */
extern t_codeattr_ptr codeattr_new();

/**
 * Make a pseudo copy of attribute object.
 *
 * The pseudo copy is just a reference to source attribute, and
 * if either object is modified, another one changes in the same way.
 *
 * @note Caller should use tree_set_annotation() to record
 *       the returned object in parse tree node.
 *
 * @note The returned object should be destroyed through codeattr_destroy().
 *
 * @param src  pointer to the source object tobe copy
 * @return A pseudo copy of attribute object pointed to by src.
 */
extern t_codeattr_ptr codeattr_getReference(t_codeattr_ptr src);

/**
 * Make a shallow copy of attribute object.
 *
 * The copy is a new object, and each field has the same value
 * as the corresponding field of source object.
 *
 * @note Caller should use tree_set_annotation() to record
 *       the returned object in parse tree node.
 *
 * @note The returned object should be destroyed through codeattr_destroy().
 *
 * @param src  pointer to the source object tobe copy
 * @return A shallow copy of attribute object pointed to by src.
 */
extern t_codeattr_ptr codeattr_copy(t_codeattr_ptr src);

/**
 * Destroy a attribute object.
 *
 * @note This function should be called during destroying the parse tree
 *       if the attribute object has recorded in parse tree
 *       by tree_set_annotation().
 *
 * @param attrPtr  pointer to the attribute object
 * @see emitter_module_init() in emitter.c
 */
extern void codeattr_destroy(void * attrPtr);


/**
 * Class ircodemgr, a manager for IR-codes
 */
struct ircode_manager {
    t_emitter_ptr   emitterPtr; // the IR-code emitter

    // List of all func_code_pairs in source program.
    // The underlying type is list<t_func_code_pair*>.
    // A new element is appended immediately
    //   AFTER a function has been analyzed.
    t_program_codes  programCodes;

    t_ir_address_ptr  trueAddress;  // to represent 1
    t_ir_address_ptr  falseAddress; // to represent 0
};

typedef struct ircode_manager t_ircodemgr, * t_ircodemgr_ptr;
typedef struct ircode_manager t_codemgr,   * t_codemgr_ptr ;



/**
 * @brief Creates a new IR-code manager.
 *
 * @param emitterPtr  pointer to the emitter
 * @return pointer to the new IR-code manager.
 */
extern t_codemgr_ptr  codemgr_new(t_emitter_ptr emitterPtr);

/**
 * @brief  Destroy the specified IR-code manager.
 * @param pThis  pointer to IR-code manager
 */
extern void codemgr_destroy(t_codemgr_ptr pThis);

/**
 * @brief  Get the id for next new ir-code.
 *
 * @param pThis  pointer to IR-code manager
 * @return return the "nextstat" in section 4.8~4.9 of our textbook
 */
extern t_ircode_id  codemgr_nextstat(t_codemgr_ptr pThis);

/**
 * @brief  Emit a new three-address-code.
 *
 * @param pThis pointer to IR-code manager
 * @param op    operation code of new ir-code
 * @param arg1  the "arg1" in three-address-code
 * @param arg2  the "arg2" in three-address-code
 * @param result  the "result" in three-address-code
 *
 * @return Return a pointer to a new ir-code.
 * @note The returned ir-code has been recorded in code-list.
 */
extern t_ircode_ptr codemgr_emit(t_codemgr_ptr pThis, EnumOpCode op,
                                 t_ir_address_ptr arg1,
                                 t_ir_address_ptr arg2,
                                 t_ir_address_ptr result);


/** Create an address object representing a temporary variable
    in three-address-code.
*/
extern t_ir_address_ptr codemgr_newTempVar(t_codemgr_ptr pThis);

/** Create an address object representing a concrete integer
    in three-address-code.
*/
extern t_ir_address_ptr codemgr_newNumber(t_codemgr_ptr pThis, t_ircode_id  num);

/**  Create an address object representing a literal or variable
     of source program in three-address-code.
*/
extern t_ir_address_ptr codemgr_newToken(t_codemgr_ptr pThis, t_tree_ptr tokenNode);

/** Create an address object representing unknown target of goto instruction.
 */
extern t_ir_address_ptr codemgr_unknownJumpAddress(t_codemgr_ptr pThis);

/**
 * @brief  Prepare to analyze a function.
 *
 * This function is called when emitter enters into a function definition.
 *
 * @param pThis          pointer to this ircodemgr
 * @param funcDeclNode   tree root of a function definition
 *                       (marked by funcDeclaration or translationUnit)
 */
extern void codemgr_entry_func(t_codemgr_ptr pThis, t_tree_ptr funcDeclNode);

/**
 * @brief  Finish analyzing a function.
 *
 * This function is called when emitter exits from a function definition.
 *
 * @param pThis      pointer to this ircodemgr
 */
extern void codemgr_exit_func(t_codemgr_ptr pThis);

/**
 * @brief  Get the data-type of a variable, a function or an expression.
 *
 * The specific tree node is marked by ID(name) of a variable or function,
 * or is marked by a non-terminal describing any expressions.
 *
 * @param node  parse tree node
 * @return Return a pointer to the type object, or
 *         return NULL if the type is not available.
 */
extern t_type_ptr codemgr_getDataType(t_tree_ptr node);


// Some magic number

#define  RETCODE_MISS_RETURN  710071
#define  RETCODE_MISS_VAL     10701
#define  RETCODE_MISS_ATTR    INT_MIN



AMCC_DECL_END

#endif //AMCC_IRCODE_MGR_H
